﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;

namespace Expression表达式目录树
{
    public class Program
    {
        /// <summary>
        /// 表达式目录树是一种数据接口 
        /// 专门为Linq to Sql准备的
        /// </summary>
        /// <param name="args"></param>
        static void Main(string[] args)
        {
            //认识Expression
            {
                //我们把这里当成一个数据源
                List<Student> students = new List<Student>();
                //我们在用ORM框架的时候经常出现以下的场景 ，我们的Where中传入的就是
                ///Expression<Func<TSource, bool>> predicate 在没有学这个东西的时候我也知道这是一个什么
                ///只知道可以传入lambda表达式赛选数据
                var daa = students.AsQueryable().Where(x => x.ID == 15);
            }

            //Expression介绍
            {
                //这里我们看这着和委托差不多，但是它还真不是委托
                Expression<Func<int, int>> expression = x => x + 10;
                //Compile方法可以将Expression转换成委托
                Func<int, int> func = expression.Compile();
                //直接声明委托
                Func<int, int> func1 = x => x + 10;
                Console.WriteLine("转换之后的委托--" + func.Invoke(5));
                Console.WriteLine("委托--" + func1.Invoke(5));
            }

            //表单式目录树解析1
            //参数
            {
                //直接使用lambda表达式创建
                Expression<Func<int, int, int>> expression = (m, n) => m * n + 3;

                //下面我们使用原始的方式创建一个Expression<Func<int, int, int>>

                //创建一个m参数 这里的参数是值的（m,n）的，如果说你有几个参数就创建几个
                ParameterExpression parameter = Expression.Parameter(typeof(int), "m");

                //创建一个n参数
                ParameterExpression parameter1 = Expression.Parameter(typeof(int), "n");

                //创建一个常量3
                ConstantExpression constant = Expression.Constant(3, typeof(int));

                //首先算出最左边的m*n的结果
                BinaryExpression binaryExpression = Expression.Multiply(parameter, parameter1);

                //然后算出(m*n)+3的结果
                binaryExpression = Expression.Add(binaryExpression, constant);

                //将上面分解的步骤拼接成lambda
                Expression<Func<int, int, int>> expression1 = Expression.Lambda<Func<int, int, int>>(binaryExpression, new ParameterExpression[]
                {
                    parameter,
                    parameter1
                });
                Console.WriteLine("lambda表达式方式--" + expression.Compile()(5, 6));
                Console.WriteLine("自己写的组装" + expression1.Compile()(5, 6));
            }

            //表单式目录树解析2
            //方法
            {
                //使用lambda带方法
                Expression<Func<Student, bool>> expression = x => x.ID.Equals(15);
                //首先还是定义一个x参数对于上面的x的参数
                ParameterExpression parameter = Expression.Parameter(typeof(Student), "x");
                //首先我们还是从左边进行拆分 获取到属性
                MemberExpression property = Expression.Property(parameter, typeof(Student).GetProperty("ID"));
                //获取我们的方法
                MethodInfo equals = typeof(Student).GetMethod("Equals");
                //定义我们的常量
                ConstantExpression constant = Expression.Constant("15", typeof(string));
                //定义一个方法拼接、第一个参数是我们的属性，第二个参数是使用的方法，第三个参数是传入方法的参数
                MethodCallExpression coll = Expression.Call(property, equals, new Expression[] { constant });
                //所有的数据解析完了之后，我们就需要将参数、方法进行拼装了
                Expression<Func<Student, bool>> expression1 = Expression.Lambda<Func<Student, bool>>(coll, new ParameterExpression[] {
                parameter
                });
                Student student = new Student
                {
                    ID = 15
                };
                Console.WriteLine("lambda表达式方式--" + expression.Compile()(student));
                Console.WriteLine("自己组装方式--" + expression1.Compile()(student));
            }

            //表单式目录树解析2
            //对象转换
            {
                Student student = new Student
                {
                    ID = 15,
                    Name = "产品粑粑",
                    Age = 18
                };
                //硬编码
                {
                    //硬编码转换
                    StudentModel studentModel = new StudentModel
                    {
                        ID = student.ID,
                        Name = student.Name,
                        Age = student.Age
                    };
                }

                //反射转换
                {
                    StudentModel studentModel = new StudentModel();
                    Type type1 = student.GetType();
                    Type type2 = studentModel.GetType();
                    foreach (var item in type2.GetProperties())
                    {
                        //判断是不是存在
                        if (type1.GetProperty(item.Name) != null)
                        {
                            item.SetValue(studentModel, type1.GetProperty(item.Name).GetValue(student));
                        }
                    }
                }

                //下买的两种方法主要是通过保存第一次生成的委托进行保存
                //第二次先判断存不存在这次要组装的委托，如果有直接取出之前的委托进行换
                //字典的还是要比泛型委托的慢一点，因为要去找字典里面存在吗?泛型委托直接获取
                {
                    //表达式目录树之字典
                    {
                        StudentModel studentModel = new StudentModel();
                        for (int i = 0; i < 10; i++)
                        {
                            studentModel = DictionariesExpand<Student, StudentModel>.ToObj(student);
                        }
                    }

                    //表达式目录树之泛型
                    {
                        StudentModel studentModel = new StudentModel();
                        for (int i = 0; i < 10; i++)
                        {
                            var data = GenericityExpand<Student, StudentModel>.ToObj(student);
                        }
                    }
                }
            }

            Console.WriteLine("Hello World!");
        }
    }
}
